package com.crud.generator;

import freemarker.core.ParseException;
import freemarker.template.*;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description: 通用controller、service生成插件
 *
 * @Author: RenTie
 * @Date: 2018-08-21 10:47
 **/
public class CrudPlugin extends PluginAdapter{
    @Override
    public boolean validate(List<String> list) {
        return true;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

        String javaMapperType = introspectedTable.getMyBatis3JavaMapperType();
        //service存放路径
        String servicePath = this.properties.getProperty("servicePath");

        //controller存放路径
        String controllerPath = this.properties.getProperty("controllerPath");

        //页面存放路径
        String htmlPath = this.properties.getProperty("htmlPath");

        //页面使用的框架
        String pageFrame = this.properties.getProperty("pageFrame");

        //通用service依赖路径
        String baseService = this.properties.getProperty("baseService");

        //通用service实现依赖路径
        String baseServiceImpl = this.properties.getProperty("baseServiceImpl");

        //获取实体类路径
        String modelPath = this.getContext().getJavaModelGeneratorConfiguration().getTargetPackage();

        //实体类名
        String javaClassName = javaMapperType.substring(javaMapperType.lastIndexOf('.') + 1, javaMapperType.length()).replace("Mapper", "");
        //项目的根路径
        String targetProject = this.getContext().getJavaClientGeneratorConfiguration().getTargetProject();

        //资源路径，用于存放页面
        String resourcePath = this.getContext().getSqlMapGeneratorConfiguration().getTargetProject();

        //获取所有字段的封装
        List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();

        //所有字段名
        List<String> columns = new ArrayList<>();
        allColumns.forEach(c->{
            columns.add(c.getJavaProperty());
        });

        Map<String, Object> root = new HashMap<String, Object>();
        root.put("columns",columns);
        root.put("servicePath", servicePath);
        root.put("controllerPath", controllerPath);
        root.put("baseService", baseService);
        root.put("modelPath", modelPath);
        root.put("baseServiceImpl", baseServiceImpl);
        root.put("EntityName", javaClassName);
        root.put("entityName", new StringBuilder().append(Character.toLowerCase(javaClassName.charAt(0)))
                .append(javaClassName.substring(1)).toString());

        //service生成
        serviceGenerator(targetProject, servicePath, javaClassName, root);
        //controller生成
        controllerGenerator(targetProject, controllerPath, javaClassName, root);

        if (htmlPath != null && !htmlPath.isEmpty()) {
            //页面生成
            htmlGenerator(resourcePath, pageFrame, htmlPath, javaClassName, root);
        }
        return null;
    }

    /**
     * 生成Service接口及其实现类
     * @param targetProject 项目的根路径
     * @param servicePath 存放service接口的路径
     * @param javaClassName 实体类名
     * @param root 传入模版的参数
     */
    public void serviceGenerator(String targetProject, String servicePath, String javaClassName, Map<String, Object> root) {

        //Service接口存放路径
        String serviceDirPath = targetProject + "/" + servicePath.replaceAll("\\.", "/");
        String serviceFilePath = targetProject + "/" + servicePath.replaceAll("\\.", "/")+"/"+ javaClassName
                + "Service.java";

        //Service实现类存放路径
        String serviceImplDirPath = targetProject + "/" + servicePath.replaceAll("\\.", "/")+"/impl";
        String serviceImpFilePath = targetProject + "/" + servicePath.replaceAll("\\.", "/")+"/impl/" +javaClassName
                + "ServiceImpl.java";

        File serviceDir = new File(serviceDirPath);
        File serviceFile = new File(serviceFilePath);
        File serviceImplDir = new File(serviceImplDirPath);
        File serviceImpFile = new File(serviceImpFilePath);
        if (serviceFile.exists()) {
            System.err.println(serviceFile + " already exists, it was skipped.");
            return;
        } else {
            try {
                serviceDir.mkdirs();
                serviceFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (serviceImpFile.exists()) {
            System.err.println(serviceImpFile + " already exists, it was skipped.");
            return;
        } else {
            try {
                serviceImplDir.mkdirs();
                serviceImpFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        cfg.setClassForTemplateLoading(this.getClass(), "/");
        cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_23));


        try {
            Template temp = cfg.getTemplate("EntityService.ftl");
            Writer out = new OutputStreamWriter(new FileOutputStream(serviceFile));
            temp.process(root, out);
            out.flush();

            System.err.println("Saving file "+javaClassName+"Service.java");
            temp = cfg.getTemplate("EntityServiceImpl.ftl");
            out = new OutputStreamWriter(new FileOutputStream(serviceImpFile));
            temp.process(root, out);
            out.flush();
            System.err.println("Saving file "+javaClassName+"ServiceImpl.java");
        } catch (TemplateNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }

    }

    /**
     * 生成controller类
     * @param targetProject 项目的根路径
     * @param controllerPath 存放controller类的路径
     * @param javaClassName 实体类名
     * @param root 传入模版的参数
     */
    public void controllerGenerator(String targetProject, String controllerPath, String javaClassName, Map<String, Object> root) {

        //Service接口存放路径
        String controllerDirPath = targetProject + "/" + controllerPath.replaceAll("\\.", "/");
        String controllerFilePath = targetProject + "/" + controllerPath.replaceAll("\\.", "/")+"/"+ javaClassName
                + "Controller.java";

        File dir = new File(controllerDirPath);
        File file = new File(controllerFilePath);

        if (file.exists()) {
            System.err.println(file + " already exists, it was skipped.");
            return;
        } else {
            try {
                dir.mkdirs();
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        cfg.setClassForTemplateLoading(this.getClass(), "/");
        cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_23));


        try {
            Template temp = cfg.getTemplate("EntityController.ftl");
            Writer out = new OutputStreamWriter(new FileOutputStream(file));
            temp.process(root, out);
            out.flush();
            System.err.println("Saving file "+javaClassName+"Controller.java");

        } catch (TemplateNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }

    }

    /**
     * 生成基础增删改查页面
     * @param targetProject 项目的根路径
     * @param frame 使用的前端框架
     * @param htmlPath 页面存放路径
     * @param javaClassName 实体类名
     * @param root 传入模版的参数
     */
    public void htmlGenerator(String targetProject,String frame, String htmlPath, String javaClassName, Map<String, Object> root) {

        //Service接口存放路径
        String dirPath = targetProject + "/" + htmlPath;
        String page1Path = targetProject + "/" + htmlPath+"/"+ javaClassName + "Manager.html";
        String page2Path = targetProject + "/" + htmlPath+"/"+ javaClassName + "Add.html";
        String page3Path = targetProject + "/" + htmlPath+"/"+ javaClassName + "Edit.html";

        File dir = new File(dirPath);
        File file1 = new File(page1Path);
        File file2 = new File(page2Path);
        File file3 = new File(page3Path);

        if (file1.exists()) {
            System.err.println(file1 + " already exists, it was skipped.");
            return;
        } else {
            try {
                dir.mkdirs();
                file1.createNewFile();
                file2.createNewFile();
                file3.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        cfg.setClassForTemplateLoading(this.getClass(), "/");
        cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_23));


        try {
            Template temp1 = cfg.getTemplate(frame+"/EntityManager.ftl");
            Writer out1 = new OutputStreamWriter(new FileOutputStream(file1));
            temp1.process(root, out1);
            out1.flush();
            System.err.println("Saving file "+javaClassName+"Manager.html");

            Template temp2 = cfg.getTemplate(frame+"/EntityAdd.ftl");
            Writer out2 = new OutputStreamWriter(new FileOutputStream(file2));
            temp2.process(root, out2);
            out2.flush();
            System.err.println("Saving file "+javaClassName+"Add.html");

            Template temp3 = cfg.getTemplate(frame+"/EntityEdit.ftl");
            Writer out3 = new OutputStreamWriter(new FileOutputStream(file3));
            temp3.process(root, out3);
            out3.flush();
            System.err.println("Saving file "+javaClassName+"Edit.html");


        } catch (TemplateNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }

    }

}
